﻿using SocketCore.Common.Config;
using SocketCore.Common.Event;
using SocketCore.Common.Heartbeat;
using System.Buffers;
using System.Net.Sockets;

namespace SocketCore.Common.Message
{
    /// <summary>
    /// 构造
    /// </summary>
    /// <param name="socketConfig"></param>
    /// <param name="isServer"></param>
    public class MessageManager(SocketConfig socketConfig, bool isServer)
    {
        /// <summary>
        /// 配置
        /// </summary>
        private readonly SocketConfig _socketConfig = socketConfig;

        /// <summary>
        /// 服务类型
        /// </summary>
        public readonly string ServerType = isServer ? "客户端" : "服务端";

        /// <summary>
        /// 接收消息
        /// </summary>
        /// <param name="clientSocket"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public async Task ReceiveMessagesAsync(Socket clientSocket, ClientHeartbeatState clientHeartbeatState, CancellationToken cancellationToken)
        {
            // 使用ArrayPool减少内存分配
            var buffer = ArrayPool<byte>.Shared.Rent(_socketConfig.ReceiveBufferSize);

            try
            {
                int bytesRead = 0;

                while (!cancellationToken.IsCancellationRequested && clientSocket.Connected)
                {
                    // 异步接收数据
                    int received = await clientSocket.ReceiveAsync(
                        new ArraySegment<byte>(buffer, bytesRead, buffer.Length - bytesRead),
                        SocketFlags.None,
                        cancellationToken);

                    if (received == 0)
                    {
                        // 客户端断开连接
                        // 触发重连
                        _socketConfig.EventHub.ConnectionLost?.Invoke();
                        _socketConfig.EventHub.RaiseEvent(SocketEventType.ClientDisconnected, clientSocket);
                        break;
                    }

                    bytesRead += received;

                    // 处理所有完整的消息
                    int processed = 0;
                    while (processed < bytesRead)
                    {
                        // 检查是否有足够的字节读取消息头
                        if (bytesRead - processed < MessageProtocol.HEADER_SIZE)
                            break;

                        // 读取消息长度
                        int messageLength = BitConverter.ToInt32(buffer, processed);

                        // 检查是否有完整的消息
                        if (bytesRead - processed < MessageProtocol.HEADER_SIZE + messageLength)
                            break;

                        // 解析消息
                        var message = MessageProtocol.Deserialize(buffer, processed, MessageProtocol.HEADER_SIZE + messageLength);

                        clientHeartbeatState.LastHeartbeatTime = DateTime.UtcNow;

                        // 处理不同类型的消息
                        if (message.Type == MessageProtocol.MessageType.Heartbeat)
                        {
                            _socketConfig.EventHub.RaiseEvent(SocketEventType.Heartbeat, new SocketHeartbeatMessage { Message = $"收到{ServerType}[{clientSocket.RemoteEndPoint}]发送的心跳消息" });
                            // 发送确认响应
                            await SendAsync(clientSocket, MessageProtocol.Message.CreateAck(clientHeartbeatState.NextMessageId++));
                        }
                        else if (message.Type == MessageProtocol.MessageType.Ack)
                        {
                            int ackId = BitConverter.ToInt32(message.Data, 0);
                            _socketConfig.EventHub.RaiseEvent(SocketEventType.Heartbeat, new SocketHeartbeatMessage { Message = $"收到{ServerType}[{clientSocket.RemoteEndPoint}]的心跳消息确认响应" });
                        }
                        else
                        {
                            _socketConfig.EventHub.RaiseEvent(SocketEventType.MessageReceived, new SocketClientMessage { ClientInfo = clientSocket.RemoteEndPoint.ToString(), Message = message.GetText() });
                        }

                        // 移动已处理的消息
                        processed += MessageProtocol.HEADER_SIZE + messageLength;
                    }

                    // 将未处理的数据移动到缓冲区开头
                    if (processed > 0)
                    {
                        int remaining = bytesRead - processed;
                        if (remaining > 0)
                        {
                            Array.Copy(buffer, processed, buffer, 0, remaining);
                        }
                        bytesRead = remaining;
                    }
                }
            }
            catch (SocketException ex) when (ex.SocketErrorCode == SocketError.ConnectionReset)
            {
                // 连接被重置
                _socketConfig.EventHub.RaiseEvent(SocketEventType.Log, new SocketLogMessage { Level = LogLevel.Warning, Message = $"{ServerType}连接被重置" });

                // 触发重连
                _socketConfig.EventHub.ConnectionLost?.Invoke();
                _socketConfig.EventHub.RaiseEvent(SocketEventType.ClientDisconnected, clientSocket);
            }
            catch (OperationCanceledException)
            {
                // 接收被取消
            }
            catch (Exception ex)
            {
                // 如果是连接相关的错误，触发重连
                if (IsConnectionError(ex))
                {
                    _socketConfig.EventHub.ConnectionLost?.Invoke();
                    _socketConfig.EventHub.RaiseEvent(SocketEventType.ClientDisconnected, clientSocket);
                }
                else
                {
                    _socketConfig.EventHub.RaiseEvent(SocketEventType.Log, new SocketLogMessage { Level = LogLevel.Error, Message = $"接收{ServerType}消息时发生错误：{ex.Message}", Exception = ex });
                }
            }
            finally
            {
                // 释放缓冲区
                ArrayPool<byte>.Shared.Return(buffer);
            }
        }

        /// <summary>
        /// 连接错误检测方法
        /// </summary>
        /// <param name="ex"></param>
        /// <returns></returns>
        private bool IsConnectionError(Exception ex)
        {
            return ex is SocketException ||
                   ex is IOException ||
                   ex.Message.Contains("连接") ||
                   ex.Message.Contains("connection");
        }

        /// <summary>
        /// 发送消息
        /// </summary>
        /// <param name="clientSocket"></param>
        /// <param name="message"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public async Task SendAsync(Socket clientSocket, MessageProtocol.Message message, CancellationToken? cancellationToken = null)
        {
            if (clientSocket == null || !clientSocket.Connected)
            {
                _socketConfig.EventHub.RaiseEvent(SocketEventType.Log, new SocketLogMessage { Level = LogLevel.Warning, Message = $"尝试发送消息到已断开的连接: {clientSocket?.RemoteEndPoint}" });
                // 触发客户端断开事件
                _socketConfig.EventHub.RaiseEvent(SocketEventType.ClientDisconnected, clientSocket);
                return;
            }

            try
            {
                var data = MessageProtocol.Serialize(message);
                if (cancellationToken != null)
                {
                    await clientSocket.SendAsync(data, SocketFlags.None, cancellationToken.Value);
                }
                else
                {
                    await clientSocket.SendAsync(data, SocketFlags.None);
                }
                switch (message.Type)
                {
                    case MessageProtocol.MessageType.Text:
                        _socketConfig.EventHub.RaiseEvent(SocketEventType.Log, new SocketLogMessage { Level = LogLevel.Info, Message = $"发送消息给[{clientSocket.RemoteEndPoint}]{ServerType}：{message.GetText()}" });
                        break;

                    case MessageProtocol.MessageType.Heartbeat:
                        _socketConfig.EventHub.RaiseEvent(SocketEventType.Heartbeat, new SocketHeartbeatMessage { Message = $"发送{ServerType}[{clientSocket.RemoteEndPoint}]心跳消息" });
                        break;

                    case MessageProtocol.MessageType.Ack:
                        _socketConfig.EventHub.RaiseEvent(SocketEventType.Heartbeat, new SocketHeartbeatMessage { Message = $"响应{ServerType}[{clientSocket.RemoteEndPoint}]发送的心跳消息" });
                        break;

                    case MessageProtocol.MessageType.Command:
                        break;

                    default:
                        break;
                }
            }
            catch (SocketException ex)
            {
                _socketConfig.EventHub.RaiseEvent(SocketEventType.Log, new SocketLogMessage { Level = LogLevel.Error, Message = $"发送消息给[{clientSocket.RemoteEndPoint}]{ServerType}时发生错误：{ex.Message}", Exception = ex });
                // 触发客户端断开事件
                _socketConfig.EventHub.RaiseEvent(SocketEventType.ClientDisconnected, clientSocket);
            }
            catch (Exception ex)
            {
                _socketConfig.EventHub.RaiseEvent(SocketEventType.Log, new SocketLogMessage { Level = LogLevel.Error, Message = $"发送消息给[{clientSocket.RemoteEndPoint}]{ServerType}时发生错误：{ex.Message}", Exception = ex });
            }
        }
    }
}